﻿/*
 * Copyright (c) United Binary LLC.  All rights reserved.
 * 
 * This code is licensed under the MIT License
 * 
 * SEE: http://harnessit.codeplex.com/license
 * 
 */
using System;
using System.Windows.Forms;
using UnitedBinary.HarnessIt.SharedTypes;
using UnitedBinary.UnitTests.Framework;
using System.Collections.Generic;
using System.Drawing;
using System.ComponentModel;

namespace UnitedBinary.HarnessIt.Controls
{
	[DefaultEvent("MethodSelected")]
	public partial class TestStatusControl : UserControl
	{
		public event EventHandler<TestMethodArgs> MethodSelected;

		private List<IMethod> testMethods = new List<IMethod>(10000);
		private Dictionary<IMethod, int> methodToIndexDic = new Dictionary<IMethod, int>(1000);
		private List<ListViewItem> listResults = new List<ListViewItem>(10000);

		public TestStatusControl()
		{
			InitializeComponent();
			TestStatusControlColumnState state = new TestStatusControlColumnState(this.listViewResults);
			state.Initalize();
		}

		public void Clear()
		{
			testMethods.Clear();
			methodToIndexDic.Clear();
			this.listViewResults.Items.Clear();

			labelStatus.BackColor = SystemColors.Control;
			labelStatus.Text = "";
		}

		public void AddTestResult(IMethod method)
		{
			int index = testMethods.Count;
			testMethods.Add(method);
			methodToIndexDic.Add(method, index);
		}

		public void RenderResults()
		{
			lock (testMethods)
			{
				this.listViewResults.Items.Clear();
				listResults.Clear();
				this.listViewResults.BeginUpdate();
			
                List<IMethod> failures = GetFailedResults();
				foreach (IMethod method in failures)
				{
					listResults.Add(GetListItemForMethod(method));
				}

                List<IMethod> passes = GetPassedResults();
				foreach (IMethod method in passes)
				{
					listResults.Add(GetListItemForMethod(method));
				}

				this.listViewResults.Items.AddRange(listResults.ToArray());
				this.listViewResults.EndUpdate();

				SetTestStatusDisplay(failures.Count, passes.Count);
			}
		}

		private void SetTestStatusDisplay(int failCount, int passCount)
		{
			if (failCount > 0)
			{
				labelStatus.BackColor = Color.Red;
				labelStatus.Text = string.Format("   There were {0} FAILED test{1} (out of {2})", 
					failCount, failCount == 1 ? "" : "s", failCount + passCount);
			}
			else
			{
				labelStatus.BackColor = Color.Green;
				labelStatus.Text = string.Format("   All tests were successful ({0} test{1})",
					passCount, passCount == 1 ? "" : "s");
			}
		}

		private ListViewItem GetListItemForMethod(IMethod method)
		{
			//
			// Icon
			// Assertions
			// Method
			// Class
			// Assembly
			// index
			//
			string[] subItems = new[]
				{
					"",
					GetAssertionText(method),
					method.Name,
					method.ParentClass.Name,
					method.ParentClass.ParentAssembly.Name,
					methodToIndexDic[method].ToString()
				};
			ListViewItem item = new ListViewItem(subItems);
			item.ImageIndex = GetImageIndex(method);
			item.BackColor = GetBackColor(method);
			return item;
		}

		private List<IMethod> GetFailedResults()
		{
			return testMethods.FindAll(m => m.TestRecord.Failures > 0);
		}

		private List<IMethod> GetPassedResults()
		{
			return testMethods.FindAll(m => m.TestRecord.Failures == 0);
		}

		private Color LiteGreen
		{
			get
			{
				return Color.FromArgb(210, 255, 210);
			}
		}
		private Color LiteRed
		{
			get
			{
				return Color.FromArgb(255, 165, 165);
			}
		}
		private Color GetBackColor(IMethod method)
		{
			return method.TestRecord.Failures == 0 ? LiteGreen : LiteRed;
		}

		private static string GetAssertionText(IMethod method)
		{
			return string.Format("{0}/{1}",
				method.TestRecord.Successes,
				method.TestRecord.TestCount);
		}

		private int GetImageIndex(IMethod method)
		{
			return method.TestRecord.Failures == 0 ? 0 : 1;
		}

		private void listViewResults_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (listViewResults.SelectedIndices.Count == 0)
            {
				OnMethodSelected(null);
				return;
            }

			int index = Convert.ToInt32(listViewResults.SelectedItems[0].SubItems[5].Text);
			IMethod method = testMethods[index];
			OnMethodSelected(method);
		}

		protected virtual void OnMethodSelected(IMethod method)
		{
			if (MethodSelected != null)
			{
				MethodSelected(this, new TestMethodArgs(method));
			}
		}

		private void listViewResults_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
		{
			TestStatusControlColumnState state = new TestStatusControlColumnState(this.listViewResults);
			state.Save();
		}

		internal void TestsStarting()
		{
			labelStatus.BackColor = Color.Black;
			labelStatus.Text = "Executing tests, please wait...";
		}
	}
}